package com.github.florent37.rxjsoup; import org.jetbrains.annotations.Nullable; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.ObservableSource; import io.reactivex.annotations.NonNull; import io.reactivex.functions.Function; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class RxJsoup { private static final String TAG = "RXJSOUP"; private final String url; private Document document; @Nullable private OkHttpClient okHttpClient = null; private boolean exceptionIfNotFound = false; public RxJsoup(String url, boolean exceptionIfNotFound, OkHttpClient okHttpClient) { this.url = url; this.exceptionIfNotFound = exceptionIfNotFound; this.okHttpClient = okHttpClient; } //RxJsoup.connect( // Jsoup.connect("www.gggggggg.fr") // .userAgent(MY_USER_AGENT) // .data("credential", email) // .data("pwd", password) // .cookies(loginForm.cookies()) // .method(Connection.Method.POST) // // ).subscibe( response -> {}) public static Observable<Connection.Response> connect(final Connection jsoupConnection) { return Observable.create(new ObservableOnSubscribe<Connection.Response>() { @Override public void subscribe(ObservableEmitter<Connection.Response> observableEmitter) throws Exception { try { final Connection.Response response = jsoupConnection.execute(); observableEmitter.onNext(response); observableEmitter.onComplete(); } catch (Exception e) { observableEmitter.onError(e); } } }); } public RxJsoup setExceptionIfNotFound(boolean exceptionIfNotFound) { this.exceptionIfNotFound = exceptionIfNotFound; return this; } public RxJsoup with(String url) { return new RxJsoup(url, false, null); } public Observable<String> attr(final Element element, final String expression, final String attr) { return Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception { final Elements elements = element.select(expression); if (elements.isEmpty() && exceptionIfNotFound) { observableEmitter.onError(new NotFoundException(expression, element.toString())); } else { for (Element e : elements) { observableEmitter.onNext(e.attr(attr)); } observableEmitter.onComplete(); } } }); } public Observable<String> href(Element element, String expression) { return attr(element, expression, "href"); } public Observable<String> src(Element element, String expression) { return attr(element, expression, "src"); } public Observable<String> text(final Element element, final String expression) { return Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception { final Elements elements = element.select(expression); if (elements.isEmpty() && exceptionIfNotFound) { observableEmitter.onError(new NotFoundException(expression, element.toString())); } else { for (Element e : elements) { observableEmitter.onNext(e.text()); } observableEmitter.onComplete(); } } }); } private Observable<Document> document() { if (document != null) { return Observable.just(document); } else { return Observable.create(new ObservableOnSubscribe<Document>() { @Override public void subscribe(final ObservableEmitter<Document> observableEmitter) throws Exception { if (okHttpClient != null) { final Request request = new Request.Builder() .url(url) .get() .build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { observableEmitter.onError(e); } @Override public void onResponse(Call call, Response response) throws IOException { document = Jsoup.parse(response.body().string(), url); observableEmitter.onNext(document); observableEmitter.onComplete(); } }); } else { //use default jsoup http client try { document = Jsoup.connect(url).get(); observableEmitter.onNext(document); observableEmitter.onComplete(); } catch (Exception e) { observableEmitter.onError(e); } } } }); } } //example public Observable<Element> select(final String expression) { return document().flatMap( new Function<Document, ObservableSource<Element>>() { @Override public ObservableSource<Element> apply(@NonNull final Document document) throws Exception { return Observable.create(new ObservableOnSubscribe<Element>() { @Override public void subscribe(ObservableEmitter<Element> observableEmitter) { final Elements elements = document.select(expression); if (elements.isEmpty() && exceptionIfNotFound) { observableEmitter.onError(new NotFoundException(expression, "document")); } else { for (Element element : elements) { observableEmitter.onNext(element); } observableEmitter.onComplete(); } } }); } }); } public Observable<Element> getElementsByAttributeValue(final Element element, final String key, final String value) { return Observable.create(new ObservableOnSubscribe<Element>() { @Override public void subscribe(ObservableEmitter<Element> observableEmitter) throws Exception { final Elements elements = element.getElementsByAttributeValue(key, value); if (elements.isEmpty() && exceptionIfNotFound) { observableEmitter.onError(new NotFoundException(key + " " + value, element.toString())); } else { for (Element e : elements) { observableEmitter.onNext(e); } observableEmitter.onComplete(); } } }); } private class NotFoundException extends Exception { public NotFoundException(String expression, String document) { super("`" + expression + "` not found in `" + document + "`"); } } }